package com.redis.sdk.idempotent;

import com.alibaba.fastjson.JSON;
import com.redis.sdk.RedisClusterUtils;
import com.redis.sdk.cachecore.OrderSort;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;

@Aspect
@Component
@Order(OrderSort.IDEMPOTENT)
@Slf4j
public class IdempotentAspect {

    private String prefix = "Idempotent:%s:%s-%s";

    private String huserId = "h-userId";

    @Autowired
    private RedisClusterUtils redisClusterUtils;

    @Autowired
    private HttpServletRequest httpServletRequest;

    /**
     * 拦截指定注解
     */
    @Pointcut("@annotation(com.redis.sdk.idempotent.IdmenpotentRedis)")
    public void idmenpotentRedis() {
    }

    @Around("idmenpotentRedis()")
    public Object idmenpotentRedis(ProceedingJoinPoint pjp) throws Throwable {

        this.idmenpotent(pjp);
        Object value = pjp.proceed();
        return value;
    }

    private void idmenpotent(ProceedingJoinPoint pjp) {
        log.info("开始幂等校验！");
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        IdmenpotentRedis annotation = method.getAnnotation(IdmenpotentRedis.class);

        String requestUrl = httpServletRequest.getRequestURI();
        String methodType = httpServletRequest.getMethod();
        String userId = httpServletRequest.getHeader(huserId);
        String key = String.format(prefix, StringUtils.isEmpty(userId) ? 0 : userId, methodType, requestUrl);

        Map<String, String> argsTemp = new LinkedHashMap<>();
        Object[] args = pjp.getArgs();
        int i = 0;
        for (Object arg :
                args) {
            argsTemp.put(String.valueOf(i), JSON.toJSONString(arg));
        }

        Object redisValue = redisClusterUtils.get(key);
        if (null == redisValue) {
            redisClusterUtils.set(key, argsTemp, annotation.value() * 1000);
            log.info("幂等校验通过！");
            return;
        } else {
            String s = JSON.toJSONString(argsTemp);
            String s1 = JSON.toJSONString(redisValue);
            if (s.equals(s1)) {
                throw new RuntimeException("请勿重复提交!");
            }
            redisClusterUtils.set(key, argsTemp, annotation.value() * 1000);
            log.info("幂等校验通过！");
        }
    }
}
